﻿//
// MainWindow.cs
//  Gtk Window
//
// Author: 
//  Lluis Sanchez Gual  <lluis@novell.com>
//  Fredy Ramirez <framirez@pacificcoolwave.com>
//
// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
// Copyright (C) 2011 Fredy Ramirez (http://www.pacificcoolwave.com)
//
//  Creation date: Aug 9, 2011
//  Last modification: 

/*
The MIT License

Copyright (C) 2007 Novell, Inc (http://www.novell.com)
Copyright (C) 2011 Fredy Ramirez (http://www.pacificcoolwave.com)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
 */

using System;
using Gtk;
using Mono.Addins;
using Pcw.PcwTextEditor.ExtensionModel;
using Pcw.PcwTextEditor.PcwDocument;
using System.Collections.Generic;
using System.IO;

namespace Pcw.PcwTextEditor
{
	public class MainWindow : Window
	{
		private MenuBar menu_bar;
		private Toolbar tool_bar;
		private AccelGroup accel_grp;
		
		private List <Document> documents = new List<Document>();
		private Document curr_doc;
		
		private Notebook ntb;
		
		private List<ICommand> commands = new List<ICommand>();			
		
		
		/// <summary>
		/// List of commands
		/// </summary>		
		public List <ICommand> Commands {
			get {
				return commands;
			}
		}
		
		/// <summary>
		/// The Window AccelGroup used by menu for shortcut 
		/// </summary>		
		public AccelGroup AccelGrp {
			get { 
				return accel_grp; 
			}
		}		
		
		/// <summary>
		/// The current document
		/// </summary>
		public Document CurrDocument {
			get { 
				return curr_doc; 
			}
		}

		/// <summary>
		/// List of opened documents
		/// </summary>
		public List<Document> Documents {
			get { 
				return documents; 
			}
		}		

		/// <summary>
		/// Default constructor.
		/// </summary>		
		public MainWindow () : base("")
		{		
			
			Title = "PcwTextEditor";
			Maximize();
			DeleteEvent += delete_event;
			BorderWidth = 0;
			
			InitializeComponent ();
			
		}
		
		/// <summary>
		/// Add a document to Main panel.
		/// </summary>
		/// <param name="file">
		///   <see cref="String"/>. File to be added to panel, if it exists displays its content. An
		/// empty value open a new file.
		/// </param>
		public void AddDocument (string file)
		{
			FileDocument doc = new FileDocument(file);
			AddDocument(doc);
		}

		/// <summary>
		/// Add a document to Main panel.
		/// </summary>
		/// <param name="doc">
		///   <see cref="IDocumentType"/> to be added to panel.
		/// </param>
		public void AddDocument (IDocumentType doc)
		{
			// First ensure it is not already opened
			if (VerifyFileIsOpened(doc))
				return;	
			
			SetDocument(doc);
			curr_doc.DocInfo.Open();
			ShowDocument();
			
		}
		
		/// <summary>
		/// Remove a document to Main panel.
		/// </summary>
		public void RemoveDocument ()
		{
			documents.Remove(curr_doc);
			ntb.RemovePage(ntb.Page);
			
			if (documents.Count > 0) 
				curr_doc = documents[documents.Count - 1];
			else 
				curr_doc = null;
			
			ShowDocument();
		}
		
		internal void Initialize (List<IDocumentType> docs)
		{
			
			// Create the main menu and the toolbar			
			foreach (MenuItem item in CommandManager.GetMainMenuItems ())
				menu_bar.Add(item);

			foreach (ToolItem item in CommandManager.GetToolbarItems ())
				tool_bar.Add(item);
			
			// Initialize extensions
			foreach (EditorExtension ext in AddinManager.GetExtensionObjects<EditorExtension> ()) 
				ext.Initialize ();
			
			if (docs.Count == 0) {
				AddDocument("");
			}
			else {
				foreach(IDocumentType d in docs)
					AddDocument(d);
			}
			
			ShowAll();
		}
		
		private void delete_event (object obj, DeleteEventArgs args)
		{
			Application.Quit();	
			args.RetVal = true;
		}
				
		private void InitializeComponent ()
		{
			// Main cointainer
			VBox vb = new VBox(false, 0);
			
			// Accelerator keys group for entier window.
			accel_grp = new AccelGroup();
			
			// Menu bar
			menu_bar = new MenuBar();
			
			// Tool bar
			tool_bar = new Toolbar(); 
			tool_bar.IconSize = IconSize.SmallToolbar;
			tool_bar.ToolbarStyle = ToolbarStyle.Icons;			
						
			// Notebook
			ntb = new Notebook();
			ntb.TabPos = PositionType.Top;
			ntb.Scrollable = true;
			ntb.EnablePopup = false;			
			
			// Text Editor								
			vb.PackStart(menu_bar, false, false, 0);
			vb.PackStart(tool_bar, false, false, 0);
			vb.PackEnd(ntb, true, true, 0);
			
			AddAccelGroup(accel_grp); 
			Add(vb); 
		}

		private void onDocumentCreate(Document sender)
		{
			// Notify editor extensions
			foreach (EditorExtension ext in AddinManager.GetExtensionObjects<EditorExtension> ())
				ext.OnCreateDocument ();
			
			foreach(ICommand cmd in commands)
				cmd.OnCreateDocument();
		}
		
		private void onDocumentLoad(Document sender)
		{
			// Notify editor extensions
			foreach (EditorExtension ext in AddinManager.GetExtensionObjects<EditorExtension> ())
				ext.OnLoadDocument ();			
			
			foreach(ICommand cmd in commands)
				cmd.OnLoadDocument();
		}

		private void onDocumentSave(Document sender)
		{	
			// Notify editor extensions
			foreach (EditorExtension ext in AddinManager.GetExtensionObjects<EditorExtension> ())
				ext.OnSaveDocument ();
			
			foreach(ICommand cmd in commands)
				cmd.OnSaveDocument();
		}
		
		private void onDocumentSelect(Document sender)
		{
			curr_doc = sender;

			foreach (EditorExtension ext in AddinManager.GetExtensionObjects<EditorExtension> ())
				ext.OnSelectDocument ();			
			
			foreach(ICommand cmd in commands)
				cmd.OnSelectDocument();
		}
		
		private void onDocumentClose(Document sender)
		{
			curr_doc = sender;
			RemoveDocument();
			
			// Notify editor extensions
			foreach (EditorExtension ext in AddinManager.GetExtensionObjects<EditorExtension> ())
				ext.OnCloseDocument ();	
			
			foreach(ICommand cmd in commands)
				cmd.OnCloseDocument();
		}
		
		private void onDocumentChanged(Document sender)
		{
			foreach (EditorExtension ext in AddinManager.GetExtensionObjects<EditorExtension> ())
				ext.OnChangeDocument ();
			foreach(ICommand cmd in commands)
				cmd.OnChangeDocument();
		}
		
		private bool VerifyFileIsOpened (IDocumentType doc)
		{
			foreach(Document d in documents) 
				if (d.DocInfo.NameWithExtension == doc.NameWithExtension)
					return true;
			return false;
		}
		
		private void SetDocument (IDocumentType doc)
		{
			curr_doc = new Document(ntb, doc);
			curr_doc.ViewText.SetFont("monospace", 14); // Default font
			
			documents.Add(curr_doc);
			
			curr_doc.DocumentCreate += onDocumentCreate;
			curr_doc.DocumentLoad += onDocumentLoad;
			curr_doc.DocumentSave += onDocumentSave;
			curr_doc.DocumentClose += onDocumentClose;
			curr_doc.DocumentChange += onDocumentChanged;
			curr_doc.DocumentSelect += onDocumentSelect;
			
			ntb.AppendPage(curr_doc, curr_doc.TabLabel);
		}
		
		private void ShowDocument()
		{
			ntb.ShowAll();
			if (curr_doc != null){
				ntb.CurrentPage = documents.Count - 1;
				curr_doc.GrabFocus();
			}
		}
	}
}
